﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lib.dmt.teltonika.server.TCP
{
    public class ConnectionManager
    {
        private readonly ConcurrentDictionary<string, TcpClientConnection> _connections;
        private readonly ReaderWriterLockSlim _lock;

        public int Count => _connections.Count;

        public ConnectionManager()
        {
            _connections = new ConcurrentDictionary<string, TcpClientConnection>();
            _lock = new ReaderWriterLockSlim();
        }

        public void AddConnection(TcpClientConnection connection)
        {
            if (connection == null) throw new ArgumentNullException(nameof(connection));

            _connections[connection.Id] = connection;
            connection.Disconnected += (sender, e) => RemoveConnection(connection.Id);
        }

        public bool RemoveConnection(string connectionId)
        {
            if (_connections.TryRemove(connectionId, out var connection))
            {
                connection.Dispose();
                return true;
            }
            return false;
        }

        public TcpClientConnection? GetConnection(string connectionId)
        {
            _connections.TryGetValue(connectionId, out var connection);
            return connection;
        }

        public IEnumerable<TcpClientConnection> GetAllConnections()
        {
            return _connections.Values.ToArray(); // Return copy for thread safety
        }

        public IEnumerable<TcpClientConnection> GetConnectionsByFilter(Func<TcpClientConnection, bool> predicate)
        {
            return _connections.Values.Where(predicate).ToArray();
        }

        public void Broadcast(byte[] data, Func<TcpClientConnection, bool>? filter = null)
        {
            var connections = filter != null
                ? GetConnectionsByFilter(filter)
                : GetAllConnections();

            foreach (var connection in connections)
            {
                if (connection.State == EConnectionState.Connected)
                {
                    _ = connection.SendAsync(data).ContinueWith(t =>
                    {
                        if (t.IsFaulted)
                        {
                            // Handle send errors if needed
                        }
                    });
                }
            }
        }

        public void DisconnectAll(string reason = "Server shutdown")
        {
            foreach (var connection in _connections.Values)
            {
                connection.Disconnect(reason);
            }
            _connections.Clear();
        }

        public ConnectionStatistic GetStats()
        {
            var connections = GetAllConnections().ToArray();
            return new ConnectionStatistic
            {
                TotalConnections = connections.Length,
                ActiveConnections = connections.Count(c => c.State == EConnectionState.Connected),
                TotalBytesReceived = connections.Sum(c => c.TotalBytesReceived),
                TotalBytesSent = connections.Sum(c => c.TotalBytesSent),
                AverageConnectionDuration = connections.Any()
                    ? TimeSpan.FromSeconds(connections.Average(c => (DateTime.UtcNow - c.ConnectedTime).TotalSeconds))
                    : TimeSpan.Zero
            };
        }
    }
}
